
import org.junit.jupiter.api.Test;

import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;

/**
 * Clock类是一个抽象类，它和Instant类有相似的地方，都是用时间戳表示一个UTC时间，不同的是Clock还有时区的概念。
 * Clock类有四个子类，分别是SystemClock、FixedClock、OffsetClock和TickClock，子类只能通过Clock类
 * 的静态方法获取。其实还有SourceClock子类，但没有提供获取该类的方法所以不作讨论。
 *
 * SystemClock：系统时钟，顾名思义，它的时间戳和时区分别是调用System.currentTimeMillis()方法和ZoneId.systemDefault()方法获取的。
 * FixedClock：固定的时钟，顾名思义，它的时间戳是固定的，不像SystemClock类每次获取的时间戳都是最新的。
 * OffsetClock：相比于其他Clock的子类，OffsetClock类多了一个offset变量，用来偏移时间戳的。因为Clock类没有提供修改时间戳的方法，
 *              所以想通过OffsetClock类来间接调整时间戳。OffsetClock类并没有直接修改时间戳，如何调整的看millis()方法的源码。
 * TickClock：设置时间戳的精度，如精确到秒、分钟、小时，甚至5秒、10分钟、8小时都是可以的。
 */
public class ClockDemo {
}
class ClockDemo01 {


    /**
     * system(ZoneId zone)
     * systemDefaultZone()
     * systemUTC()
     * 作用：获取SystemClock类对象，zone是用来指定时间戳的时区的，systemDefaultZone()方法获取的是操作系统设置的时区。
     */
    @Test
    public void test01(){
        Clock systemClock01 = Clock.systemDefaultZone();
        System.out.println(systemClock01); // 输出 SystemClock[Asia/Shanghai]

        Clock systemClock02 = Clock.systemUTC();
        System.out.println(systemClock02); // 输出 SystemClock[Z]

        Clock systemClock03 = Clock.system(ZoneId.of("America/Los_Angeles"));
        System.out.println(systemClock03); // 输出 SystemClock[America/Los_Angeles]
    }

    /**
     * fixed(Instant fixedInstant, ZoneId zone)
     * 作用：获取FixedClock类对象，fixedInstant是时间戳参数，zone是用来指定时间戳的时区的。
     */
    @Test
    public void test02() {
        Instant instant01 = Instant.parse("1970-01-01T00:00:00Z");
        ZoneId zoneId01 = ZoneId.of("America/Los_Angeles");
        System.out.println(Clock.fixed(instant01, zoneId01)); // 输出 FixedClock[1970-01-01T00:00:00Z,America/Los_Angeles]
    }

    /**
     * offset(Clock baseClock, Duration offsetDuration)
     * 作用：获取OffsetClock类对象，baseClock是其他时钟类，offsetDuration是时间戳的偏移量。
     */
    @Test
    public void test03() {
        Instant instant01 = Instant.parse("1970-01-01T00:00:00Z");
        ZoneId zoneId01 = ZoneId.of("America/Los_Angeles");
        Clock fixedClock01 = Clock.fixed(instant01, zoneId01);
        Clock offsetClock01 = Clock.offset(fixedClock01, Duration.ofHours(8));
        System.out.println(offsetClock01); // 输出 OffsetClock[FixedClock[1970-01-01T00:00:00Z,America/Los_Angeles],PT8H]
        System.out.println(offsetClock01.millis()); // 输出 28800000
    }

    /**
     * tick(Clock baseClock, Duration tickDuration)
     * tickMinutes(ZoneId zone)
     * tickSeconds(ZoneId zone)
     * 作用：获取TickClock类对象，baseClock是其他时钟类，tickDuration是时间戳的精度。
     */
    @Test
    public void test04() {
        Instant instant01 = Instant.parse("1970-01-01T12:30:45.100Z");
        ZoneId zoneId01 = ZoneId.of("America/Los_Angeles");
        Clock fixedClock01 = Clock.fixed(instant01, zoneId01);

        Clock tickClock01 = Clock.tick(fixedClock01, Duration.ofSeconds(1));
        long tickClock01Millis = tickClock01.millis();
        System.out.println(Instant.ofEpochMilli(tickClock01Millis)); // 输出 1970-01-01T12:30:45Z

        Clock tickClock02 = Clock.tick(fixedClock01, Duration.ofHours(1));
        long tickClock02Millis = tickClock02.millis();
        System.out.println(Instant.ofEpochMilli(tickClock02Millis)); // 输出 1970-01-01T12:00:00Z

        Clock tickClock03 = Clock.tick(fixedClock01, Duration.ofHours(8));
        long tickClock03Millis = tickClock03.millis();
        System.out.println(Instant.ofEpochMilli(tickClock03Millis)); // 输出 1970-01-01T08:00:00Z
    }
}

class ClockDemo02{

    /**
     * getZone()
     * 作用：获取时区。
     */
    @Test
    public void test01(){
        Clock systemClock01 = Clock.systemDefaultZone();
        System.out.println(systemClock01.getZone()); // 输出 Asia/Shanghai
    }

    /**
     * instant()
     * 作用：获取时间戳。
     */
    @Test
    public void test02(){
        Instant instant01 = Instant.parse("1970-01-01T12:30:45.100Z");
        ZoneId zoneId01 = ZoneId.of("Asia/Shanghai");
        Clock fixedClock01 = Clock.fixed(instant01, zoneId01);
        System.out.println(fixedClock01.instant()); // 输出 1970-01-01T12:30:45.100Z
    }

    /**
     * millis()
     * 作用：获取UTC时间戳的毫秒数，与时区无关。
     */
    @Test
    public void test03(){
        Instant instant01 = Instant.parse("1970-01-01T08:00:00Z");
        ZoneId zoneId01 = ZoneId.of("Asia/Shanghai");
        Clock fixedClock01 = Clock.fixed(instant01, zoneId01);
        System.out.println(fixedClock01.millis()); // 输出 28800000
    }

    /**
     * withZone(ZoneId zone)
     * 作用：修改时区，不修改时间戳。
     */
    @Test
    public void test04(){
        Instant instant01 = Instant.parse("1970-01-01T08:00:00Z");
        ZoneId zoneId01 = ZoneId.of("Asia/Shanghai");
        Clock fixedClock01 = Clock.fixed(instant01, zoneId01);
        Clock fixedClock02 = fixedClock01.withZone(ZoneId.of("America/Los_Angeles"));
        System.out.println(fixedClock01); // 输出 FixedClock[1970-01-01T08:00:00Z,Asia/Shanghai]
        System.out.println(fixedClock02); // 输出 FixedClock[1970-01-01T08:00:00Z,America/Los_Angeles]
    }
}